package com.dd.census.service.impl;

import com.dd.census.entity.Attendance;
import com.dd.census.entity.AttendanceDetails;
import com.dd.census.entity.Device;
import com.dd.census.entity.Parameter;
import com.dd.census.mapper.*;
import com.dd.census.service.PerformanceService;
import com.dd.census.tools.Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class PerformanceServiceImpl implements PerformanceService {

    @Autowired
    AttendanceMapper attendanceMapper;

    @Autowired
    AttendanceDetailsMapper attendanceDetailsMapper;

    @Autowired
    ParameterMapper parameterMapper;

    @Autowired
    Staff1Mapper staff1Mapper;

    @Autowired
    DeviceMapper deviceMapper;

    @Override
    public Map<String,Object> calculation(Attendance param) {
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Parameter parameter = new Parameter();
        List<Parameter> parameters = parameterMapper.selectList(parameter);
        Map<String,Double> mapParameters = new HashMap<>();
        Map<String,Object> runParam = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        AttendanceDetails attendanceDetails = new AttendanceDetails();
        for(Parameter s: parameters){
            mapParameters.put(s.getCode(),Double.valueOf( s.getValue()));
        }
        // [本月应提]成当前月上一个月 预计的人==========================================
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, -1);
        //本月实际月份（管理员核算数据用）
        Calendar ac = Calendar.getInstance();
        Attendance attendance = new Attendance();
        //管理员用类
        Attendance adminattendance = new Attendance();
        attendance.setAdEstimate(c.getTime());
        attendance.setAdUserId(param.getAdUserId());
        attendance.setLanderrole(param.getLanderrole());
        adminattendance.setAdEstimate(ac.getTime());
        adminattendance.setAdUserId(param.getAdUserId());
        adminattendance.setLanderrole(param.getLanderrole());
        // 本月应提成当前月上一个月 预计回款的人==========================================
        Double byytc = 0.0;
        List<Attendance> nowMonthTakes = attendanceMapper.nowMonthTakes(attendance);
        byytc = getCommission("adDuerec",nowMonthTakes,mapParameters,param);
        // 本月应回款情况（管理员用）
        Double byyhk = 0.0;
        List<Attendance> adminnowMonthTakes = attendanceMapper.nowMonthTakes(adminattendance);
        for (Attendance alist : adminnowMonthTakes){
            byyhk += alist.getAdDuerec();
        }
        // 本月实际提成 上个月实际汇款的人==========================================
        Double bysjtc = 0.0;
        attendanceDetails.setAttendanceMonth(sdf.format(c.getTime()));
        attendanceDetails.setUserId(String.valueOf(param.getAdUserId()));
        attendanceDetails.setLanderrole(param.getLanderrole());
        List<AttendanceDetails> bysjAttendanceDetails =attendanceDetailsMapper.selectList(attendanceDetails);
        for(AttendanceDetails s: bysjAttendanceDetails){
            bysjtc = bysjtc +s.getCommission();
        }
        // 本月实际回款总额（管理员用）本月毛利润（管理员用）本月提成情况（管理员用）
        Double bysjhk = 0.0;
        Double bymlr = 0.0;
        List<Attendance> adminnowMonthActual = attendanceMapper.nowMonthActual(adminattendance);
        for (Attendance alist:adminnowMonthActual){
            bysjhk += alist.getAdReceival();
            bymlr += alist.getAdReceival() - alist.getAdSalary();
        }
        // [上月实际提成]  上上个月实际汇款的人 三月查看1月的==========================================
        Calendar c2 = Calendar.getInstance();
        c2.add(Calendar.MONTH, -2);
        // 上月实际提成
        Double sysjtc = 0.0;
        Double sysjhk = 0.0;
        Double symlr = 0.0;
        adminattendance.setAdEstimate(c.getTime());
        // 上月实际回款总数（管理员用）
        adminnowMonthActual = attendanceMapper.nowMonthActual(adminattendance);
        for (Attendance alist:adminnowMonthActual){
            sysjhk += alist.getAdReceival();
            symlr += alist.getAdReceival() - alist.getAdSalary();
        }
        // 上月实际提成  上上个月实际汇款的人 三月查看1月的==========================================
        attendanceDetails.setAttendanceMonth(sdf.format(c2.getTime()));
        attendanceDetails.setUserId(String.valueOf(param.getAdUserId()));
        attendanceDetails.setLanderrole(param.getLanderrole());
        List<AttendanceDetails> sysjAttendanceDetails1 =attendanceDetailsMapper.selectList(attendanceDetails);
        for(AttendanceDetails s: sysjAttendanceDetails1){
            sysjtc = sysjtc +s.getCommission();
        }
        // [预计下个月]  就是当月 预计汇款日的人==========================================
        Attendance attendancenow = new Attendance();
        attendancenow.setAdEstimate(new Date());
        attendancenow.setAdUserId(param.getAdUserId());
        attendancenow.setLanderrole(param.getLanderrole());
        // 预计下个月
        Double cyyjtc = 0.0;
        List<Attendance> nowMonthTakescyyjtc = attendanceMapper.nowMonthTakes(attendancenow);
        cyyjtc = getCommission("adDuerec",nowMonthTakescyyjtc,mapParameters,param);
        if(param.getRoleId().equals("1")){
            runParam.put("sysjhk",sysjhk);
            runParam.put("byyhk",byyhk);
            runParam.put("bysjhk",bysjhk);
            runParam.put("bymlr",bymlr);
            runParam.put("bytcqk",byytc);
            runParam.put("symlr",symlr);
            return runParam;
        }else{
            runParam.put("byytc",byytc);
            runParam.put("bysjtc",bysjtc);
            runParam.put("sysjtc",Utils.doubleRetain(sysjtc));
            runParam.put("cyyjtc",cyyjtc);
            return runParam;
        }
    }

    @Override
    public Map<String, Object> calculationDetails(Attendance param) throws Exception {
        Map<String, Object> map = new HashMap<>();
        Parameter parameter = new Parameter();
        List<Parameter> parameters = parameterMapper.selectList(parameter);
        Map<String,Double> mapParameters = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        for(Parameter s: parameters){
            mapParameters.put(s.getCode(),Double.valueOf( s.getValue()));
        }
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, -1);
        Attendance attendance1 = new Attendance();
        attendance1.setAdEstimate(c.getTime());
        attendance1.setAdUserId(param.getAdUserId());
        attendance1.setLanderrole(param.getLanderrole());
        int a =c.get(Calendar.YEAR);
        int b = c.get(Calendar.MONTH) + 1;
        if(param.getTcType().equals("byytc")){
            // 本月应提成
            List<Attendance> nowMonthTakes = attendanceMapper.nowMonthTakes(attendance1);
            map=getAttendanceDetails("adDuerec",param,nowMonthTakes,mapParameters,String.valueOf(a)+'-'+String.valueOf(b));
        }else if(param.getTcType().equals("bysjtc")){
            //本月实际提成  既然是实际提成则应去Details表里查询现成保存数据即可 而不是getAttendanceDetails方法在attendance里重新计算
            DateFormat df = new SimpleDateFormat("yyyy-MM");
            Calendar c2 = Calendar.getInstance();
            c2.add(Calendar.MONTH, -1);
            Double sum = 0.0;
            AttendanceDetails attendanceDetails = new AttendanceDetails();
            attendanceDetails.setAttendanceMonth(sdf.format(c2.getTime()));
            attendanceDetails.setUserId(param.getAdUserId().toString());
            attendanceDetails.setLanderrole(param.getLanderrole());
            List<AttendanceDetails> attendanceDetails1 =attendanceDetailsMapper.selectList(attendanceDetails);
            // details2为了将1中所有角色拆分后以/分割 这样的话会使得显示为一条数据 否则多个身份多条数据
            List<AttendanceDetails> attendanceDetails2 = new ArrayList<>(); // 绩效详情计算每个员工相对每个招聘者的绩效详情，
            for(AttendanceDetails s: attendanceDetails1){
                //sum += Math.round(s.getCommission());
                sum += s.getCommission();
            }
            if (!StringUtils.isEmpty(attendanceDetails1)){
                Map<String, AttendanceDetails> map1 = new HashMap<>();
                attendanceDetails1.stream().forEach(billsNums -> {
                    AttendanceDetails last = map1.get(billsNums.getAttendanceID());
                    if(null != last){
                        billsNums.setRoleStr(billsNums.getRoleStr() +'/' + last.getRoleStr());
                        billsNums.setCommission(Utils.doubleRetain(billsNums.getCommission() + last.getCommission()));
                        map1.put(billsNums.getAttendanceID(), billsNums );
                    }else{
                        map1.put(billsNums.getAttendanceID(), billsNums);
                    }
                });
                attendanceDetails2 = map1.values().stream().collect(Collectors.toList());
            }
            map.put("item",attendanceDetails2);
            map.put("sum",Utils.doubleRetain(sum));
        }else if(param.getTcType().equals("sysjtc")){
            //上月实际提成
            DateFormat df = new SimpleDateFormat("yyyy-MM");
            Calendar c2 = Calendar.getInstance();
            c2.add(Calendar.MONTH, -2);
            Double sum = 0.0;
            AttendanceDetails attendanceDetails = new AttendanceDetails();
            //如果param.getAdYearMonth()为空说明点击上月实际提成
            //如果不为空说明点击搜索提成月份进入
            if(StringUtils.isEmpty(param.getAdYearMonth())){
                attendanceDetails.setAttendanceMonth(sdf.format(c2.getTime()));
            }else{
                attendanceDetails.setAttendanceMonth(param.getAdYearMonth());
            }
            attendanceDetails.setUserId(param.getAdUserId().toString());
            attendanceDetails.setLanderrole(param.getLanderrole());
            List<AttendanceDetails> attendanceDetails1 =attendanceDetailsMapper.selectList(attendanceDetails);
            List<AttendanceDetails> attendanceDetails2 = new ArrayList<>(); // 绩效详情计算每个员工相对每个招聘者的绩效详情，
            for(AttendanceDetails s: attendanceDetails1){
                sum = sum +s.getCommission();
            }
            if (!StringUtils.isEmpty(attendanceDetails1)){
                Map<String, AttendanceDetails> map1 = new HashMap<>();
                attendanceDetails1.stream().forEach(billsNums -> {
                    AttendanceDetails last = map1.get(billsNums.getAttendanceID());
                    if(null != last){
                        billsNums.setRoleStr(billsNums.getRoleStr() +'/' + last.getRoleStr());
                        billsNums.setCommission(Utils.doubleRetain(billsNums.getCommission() + last.getCommission()));
                        map1.put(billsNums.getAttendanceID(), billsNums );
                    }else{
                        map1.put(billsNums.getAttendanceID(), billsNums);
                    }
                });
                attendanceDetails2 = map1.values().stream().collect(Collectors.toList());
            }
            map.put("item",attendanceDetails2);
            map.put("sum",Utils.doubleRetain(sum));
        }else{
            Calendar cal = Calendar.getInstance();
            Attendance attendancenow = new Attendance();
            attendancenow.setAdEstimate(new Date());
            attendancenow.setAdUserId(param.getAdUserId());
            attendancenow.setLanderrole(param.getLanderrole());
            List<Attendance> nowMonthTakescyyjtc = attendanceMapper.nowMonthTakes(attendancenow);
            map = getAttendanceDetails("adDuerec",param,nowMonthTakescyyjtc,mapParameters,String.valueOf(cal.get(Calendar.YEAR))+'-'+String.valueOf(cal.get(Calendar.MONTH) + 1));
        }
        return map;
    }

    @Override
    public Map<String, Object> admincalculationDetails(Attendance param) throws Exception {
        Map<String, Object> map = new HashMap<>();
        List<Attendance> adlist = new ArrayList<>();
        Attendance attendance = new Attendance();
        attendance.setAdUserId(param.getAdUserId());
        attendance.setLanderrole(param.getLanderrole());
        if(param.getTcType().equals("sysjhk")||param.getTcType().equals("symlr")){
            Calendar c = Calendar.getInstance();
            c.add(Calendar.MONTH, -1);
            attendance.setAdEstimate(c.getTime());
            // 上月实际回款||上月毛利润
            double sysjhksum = 0.0;
            double symlrsum = 0.0;
            List<Attendance> nowMonthActual = attendanceMapper.nowMonthActual(attendance);
            for (Attendance nma : nowMonthActual){
                Attendance forattend = new Attendance();
                forattend.setStaff1(staff1Mapper.selectByKey(nma.getStaff1().getId().toString()));
                forattend.setAdYearMonth(nma.getAdYearMonth());
                forattend.setAdSalary(nma.getAdSalary());
                forattend.setAdReceival(nma.getAdReceival());
                forattend.setSmlr(nma.getAdReceival() - nma.getAdSalary());
                adlist.add(forattend);
                sysjhksum += forattend.getAdReceival();
                symlrsum += forattend.getSmlr();
            }
            map.put("item",adlist);
            map.put("sysjhksum", sysjhksum);
            map.put("symlrsum", symlrsum);
        }else if(param.getTcType().equals("byyhk")||param.getTcType().equals("bysjhk")||param.getTcType().equals("bymlr")){
            Calendar c = Calendar.getInstance();
            attendance.setAdEstimate(c.getTime());
            // 本月应回款||本月实际回款||本月毛利润
            double byyhksum = 0.0;
            double bysjhksum = 0.0;
            double bymlrsum = 0.0;
            double bysmlrsum = 0.0;
            List<Attendance> nowMonthActual = attendanceMapper.nowMonthTakes(attendance);
            for (Attendance nma : nowMonthActual){
                Attendance forattend = new Attendance();
                forattend.setStaff1(staff1Mapper.selectByKey(nma.getStaff1().getId().toString()));
                forattend.setAdYearMonth(nma.getAdYearMonth());
                forattend.setAdSalary(nma.getAdSalary());
                //三元表达式排除null报错
                forattend.setAdDuerec(!StringUtils.isEmpty(nma.getAdDuerec())? Double.valueOf(nma.getAdDuerec()):0.0);
                forattend.setAdReceival(!StringUtils.isEmpty(nma.getAdReceival())? Double.valueOf(nma.getAdReceival()):0.0);
                if(nma.getAdReceival() == null){
                    nma.setAdReceival(0.0);
                }
                forattend.setSmlr(forattend.getAdReceival() - forattend.getAdSalary());
                forattend.setYmlr(forattend.getAdDuerec() - forattend.getAdSalary());
                adlist.add(forattend);
                byyhksum += forattend.getAdDuerec();
                bysjhksum += forattend.getAdReceival();
                bymlrsum += forattend.getYmlr();
                bysmlrsum += forattend.getSmlr();
            }
            map.put("item",adlist);
            map.put("byyhksum", byyhksum);
            map.put("bysjhksum", bysjhksum);
            map.put("bymlrsum", bymlrsum);
            map.put("bysmlrsum", bysmlrsum);
        }else{
            map.put("",null);
        }
        return map;
    }

    private   Map<String, Object>  getAttendanceDetails(String str,Attendance param, List<Attendance> Attendances,Map<String,Double> mapParameters ,String targetMonth){
        Map<String, Object> map = new HashMap<>();
        List<AttendanceDetails> attendanceDetailList = new ArrayList<>();
        DateFormat df = new SimpleDateFormat("yyyy-MM");
        AttendanceDetails attendanceDetail;
        Double wxyjzjcb=mapParameters.get("wxyjzjcb");
        Double zptcbl=mapParameters.get("zptcbl");
        Double swtcbl=mapParameters.get("swtcbl");
        Double yytcbl=mapParameters.get("yytcbl");
        Double sum =0.0;
        for(Attendance s: Attendances){
            String typeStr = "";
            Double tc = 0.0;
            Double fp = 0.0;
            //提成=（汇款）实际汇款金额 - 当月薪资 -五险一金成本 - （实际*发票比例）- 补助 - 商务  * 提出比例
            if(null != s.getStaff1().getInvoice()){
                if( 1 == s.getStaff1().getInvoice()){
                    fp = 1.2 * 0.01;
                }else if(2 == s.getStaff1().getInvoice() || 3 == s.getStaff1().getInvoice()){
                    fp = 3 * 1.2 * 0.01;
                }else if(4 == s.getStaff1().getInvoice() ){
                    fp = 6 * 1.2 * 0.01;
                }else{
                    fp = 0.0;
                }
            }
            attendanceDetail = new AttendanceDetails();
            attendanceDetail.setName(s.getsName());
            attendanceDetail.setWeekDate(s.getStaff1().getWorktime());
            //目标月 就是生成绩效的月份
            attendanceDetail.setTargetMonth(s.getAdYearMonth());
            double business = !StringUtils.isEmpty(s.getStaff1().getBusiness())? Double.valueOf(s.getStaff1().getBusiness()):0.0;
            double subsidy = !StringUtils.isEmpty(s.getStaff1().getSubsidy())? Double.valueOf(s.getStaff1().getSubsidy()):0.0;
            // 查询该候选人是否有设备费用 如果用计算入成本
            double devicepay = 0.0;
            List<Device> dlist = deviceMapper.selectAlldecive();
            for(Device d : dlist){
                int duserid = !StringUtils.isEmpty(d.getNowuserid())? Integer.valueOf(d.getNowuserid()):0;
                int staffid = s.getStaff1().getId();
                if(duserid == staffid){
                    devicepay += Double.valueOf(d.getPrice());
                }
            }
            // 实际
            if(str.equals("adReceival")){
                attendanceDetail.setMonthRemittance(s.getAdReceival() );
            }else{
                // 预计
                attendanceDetail.setMonthRemittance(s.getAdDuerec());
            }
            // 当月成本 = 五险一金 + 当月薪资 + 发票+ 补助 + 商务
            attendanceDetail.setMonthCost(Utils.doubleRetain(wxyjzjcb + s.getAdSalary() + attendanceDetail.getMonthRemittance()*fp + business +subsidy +devicepay));
            attendanceDetail.setMonthProfit( Utils.doubleRetain(attendanceDetail.getMonthRemittance()-attendanceDetail.getMonthCost()));
            if(param.getAdUserId().toString().equals(s.getStaff1().getLeaderId()) ){
                typeStr = typeStr+"招聘者/";
                tc = tc + attendanceDetail.getMonthProfit() * zptcbl;
            }
            if(param.getAdUserId().toString().equals(s.getStaff1().getDirectorId())  && !param.getLanderrole().equals("9")){
                typeStr = typeStr+"渠道介绍人/";
                tc = tc + attendanceDetail.getMonthProfit() * swtcbl;
            }
            if(param.getAdUserId().toString().equals(s.getStaff1().getOperateId()) ){
                typeStr = typeStr+"运营者/";
                tc = tc + attendanceDetail.getMonthProfit() * yytcbl;
            }
            //去掉身份（招聘者，渠道介绍人，运营者显示时最后的‘/’）
            if(!typeStr.equals("")){
                typeStr = typeStr.substring(0, typeStr.length()-1);
            }
            attendanceDetail.setRoleStr(typeStr);
            attendanceDetail.setCommission(Utils.doubleRetain(tc));
            attendanceDetailList.add(attendanceDetail);
            sum= sum+attendanceDetail.getCommission();
        }
        map.put("item",attendanceDetailList);
        map.put("sum",sum);
        return map;
    }

    // 计算
    private Double getCommission(String str,  List<Attendance> attendanceList , Map<String,Double> mapParameters ,Attendance param){
        Double tc = 0.0;
        Double wxyjzjcb=mapParameters.get("wxyjzjcb");
        Double zptcbl=mapParameters.get("zptcbl");
        Double swtcbl=mapParameters.get("swtcbl");
        Double yytcbl=mapParameters.get("yytcbl");
        for(Attendance s: attendanceList){
            Double fp = 0.0;
            //提成=（回款）实际回款金额 - 当月薪资 -五险一金成本 - （实际*发票比例）- 补助 - 设备费用 - 商务  * 提出比例
            if(null != s.getStaff1().getInvoice()){
                if( 1 == s.getStaff1().getInvoice()){
                    fp = 1.2 * 0.01;
                }else if(2 == s.getStaff1().getInvoice() || 3 == s.getStaff1().getInvoice()){
                    fp = 3 * 1.2* 0.01;
                }else if(4 == s.getStaff1().getInvoice() ){
                    fp = 6 * 1.2 * 0.01;
                }else{
                    fp = 0.0;
                }
            }
            // 实际回款金额
            if(str.equals("adReceival")){
                double adReceival = StringUtils.isEmpty(s.getAdReceival())? Double.valueOf(s.getStaff1().getPrice()):s.getAdReceival() ;
                double adSalary = StringUtils.isEmpty(s.getAdSalary())? Double.valueOf(s.getStaff1().getSalary()):s.getAdSalary() ;
                double business = !StringUtils.isEmpty(s.getStaff1().getBusiness())? Double.valueOf(s.getStaff1().getBusiness()):0.0;
                double subsidy = !StringUtils.isEmpty(s.getStaff1().getSubsidy())? Double.valueOf(s.getStaff1().getSubsidy()):0.0;
                //设备管理费用需要遍历设备表查出设备使用者id跟员工id一致则加入设备金额计算入成本
                double devicepay = 0.0;
                List<Device> dlist = deviceMapper.selectAlldecive();
                for(Device d : dlist){
                    int duserid = !StringUtils.isEmpty(d.getNowuserid())? Integer.valueOf(d.getNowuserid()):0;
                    int staffid = s.getStaff1().getId();
                    if(duserid == staffid){
                        devicepay += Double.valueOf(d.getPrice());
                    }
                }
                // 招聘负责人
                if(param.getAdUserId().toString().equals(s.getStaff1().getLeaderId()) ){
                    tc = tc + (adReceival- adSalary -wxyjzjcb - adReceival*fp - business -subsidy -devicepay) * zptcbl;
                }
                // 渠道介绍人
                if(param.getAdUserId().toString().equals(s.getStaff1().getDirectorId()) ){
                    tc =tc + (adReceival - adSalary - wxyjzjcb - adReceival*fp- business -subsidy -devicepay) * swtcbl;
                }
                // 运营介绍人
                if(param.getAdUserId().toString().equals(s.getStaff1().getOperateId()) ){
                    tc =tc + (adReceival - adSalary - wxyjzjcb - adReceival*fp- business -subsidy -devicepay) * yytcbl;
                }
            }
            // 预计回款金额
            else{
                double adDuerec = StringUtils.isEmpty(s.getAdDuerec())? Double.valueOf(s.getStaff1().getPrice()):s.getAdDuerec() ;
                double adSalary = StringUtils.isEmpty(s.getAdSalary())? Double.valueOf(s.getStaff1().getSalary()):s.getAdSalary() ;
                double business = !StringUtils.isEmpty(s.getStaff1().getBusiness())? Double.valueOf(s.getStaff1().getBusiness()):0.0;
                double subsidy = !StringUtils.isEmpty(s.getStaff1().getSubsidy())? Double.valueOf(s.getStaff1().getSubsidy()):0.0;
                //设备管理费用需要遍历设备表查出设备使用者id跟员工id一致则加入设备金额计算入成本
                double devicepay = 0.0;
                List<Device> dlist = deviceMapper.selectAlldecive();
                for(Device d : dlist){
                    int duserid = !StringUtils.isEmpty(d.getNowuserid())? Integer.valueOf(d.getNowuserid()):0;
                    int staffid = s.getStaff1().getId();
                    if(duserid == staffid){
                        devicepay += Double.valueOf(d.getPrice());
                    }
                }
                // 招聘负责人
                if(param.getAdUserId().toString().equals(s.getStaff1().getLeaderId()) ){
                    tc = tc + (adDuerec - adSalary -wxyjzjcb - adDuerec*fp- business -subsidy -devicepay) * zptcbl;
                }
                // 渠道介绍人
                if(param.getAdUserId().toString().equals(s.getStaff1().getDirectorId()) && !param.getLanderrole().equals("9")){
                    tc =tc + (adDuerec - adSalary- wxyjzjcb - adDuerec*fp- business -subsidy -devicepay) * swtcbl;
                }
                // 运营介绍人
                if(param.getAdUserId().toString().equals(s.getStaff1().getOperateId()) ){
                    tc =tc + (s.getAdDuerec() - adSalary - wxyjzjcb - adDuerec*fp - business -subsidy -devicepay) * yytcbl;
                }
            }
        }
        return   Utils.doubleRetain(tc);
    }
}